package com.game.doudizhu.core;

import com.game.doudizhu.model.*;
import com.game.doudizhu.util.CardPatternUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class AITrainer {
    private static final Logger logger = LoggerFactory.getLogger(AITrainer.class);
    
    // 存储游戏统计数据
    private static class GameStats {
        int totalGames = 0;
        int landlordWins = 0;
        int farmerWins = 0;
        Map<String, Integer> strategySuccesses = new ConcurrentHashMap<>();
        Map<String, Integer> strategyFailures = new ConcurrentHashMap<>();
        Map<String, Double> strategyWeights = new ConcurrentHashMap<>();
        
        // 记录每种策略的平均手牌数量
        Map<String, Double> avgRemainingCards = new ConcurrentHashMap<>();
        
        // 记录出牌决策的结果
        List<PlayDecision> playHistory = new ArrayList<>();
        
        // 添加叫分相关的统计
        Map<String, Integer> bidSuccesses = new ConcurrentHashMap<>();  // 记录每个强度区间叫分成功次数
        Map<String, Integer> bidFailures = new ConcurrentHashMap<>();   // 记录每个强度区间叫分失败次数
        Map<String, Double> bidPatterns = new ConcurrentHashMap<>();    // 记录每个强度区间的最优叫分

        // 新增：阶段策略权重
        Map<String, Map<String, Double>> phaseStrategyWeights = new ConcurrentHashMap<>();

        // 新增：决策影响力统计
        Map<String, Double> decisionImpacts = new ConcurrentHashMap<>();
    }
    
    // 记录出牌决策
    private static class PlayDecision {
        Long playerId;
        boolean isLandlord;
        List<Card> handCards;
        List<Card> playedCards;
        List<Card> lastPlayedCards;
        int gameStage;
        boolean won;
        int remainingCards;
        String strategy;
        int handStrength;  // 添加手牌强度
        int bidValue;      // 添加叫分值
        
        public PlayDecision(Long playerId, boolean isLandlord, List<Card> handCards,
                          List<Card> playedCards, List<Card> lastPlayedCards,
                          int gameStage, String strategy) {
            this.playerId = playerId;
            this.isLandlord = isLandlord;
            this.handCards = new ArrayList<>(handCards);
            this.playedCards = playedCards != null ? new ArrayList<>(playedCards) : null;
            this.lastPlayedCards = lastPlayedCards != null ? new ArrayList<>(lastPlayedCards) : null;
            this.gameStage = gameStage;
            this.strategy = strategy;
            this.remainingCards = handCards.size();
        }
    }
    
    private static GameStats gameStats = new GameStats();
    private static final int TRAINING_BATCH_SIZE = 1000;  // 每批训练游戏数
    private static final double LEARNING_RATE = 0.1;      // 学习率
    
    public static void startTraining() {
        logger.info("开始AI训练...");
        
        // 加载已有模型
        AIModelPersistence.AIModel existingModel = AIModelPersistence.loadModel();
        if (existingModel != null) {
            gameStats.strategyWeights.putAll(existingModel.strategyWeights);
            gameStats.avgRemainingCards.putAll(existingModel.averageRemainingCards);
        }
        
        for (int batch = 0; batch < 10; batch++) {
            trainBatch(TRAINING_BATCH_SIZE);
            analyzeAndUpdateStrategies();
            logTrainingProgress(batch);
            
            // 每个批次后保存模型
            saveCurrentModel();
        }
    }
    
    private static void trainBatch(int batchSize) {
        for (int i = 0; i < batchSize; i++) {
            runTrainingGame();
        }
    }
    
    private static void runTrainingGame() {
        GameState gameState = new GameState();
        Map<Long, List<Card>> playerCards = dealCards();
        List<PlayDecision> gameDecisions = new ArrayList<>();
        
        // 设置初始玩家ID（随机选择一个玩家开始叫分）
        List<Long> allPlayerIds = new ArrayList<>(playerCards.keySet());
        Collections.shuffle(allPlayerIds);
        gameState.setCurrentPlayerId(allPlayerIds.get(0));
        
        // 叫分阶段
        Long landlordId = handleBiddingPhase(gameState, playerCards);
        if (landlordId == null) return;
        
        // 设置地主为第一个出牌的玩家
        gameState.setCurrentPlayerId(landlordId);
        
        // 游戏主循环
        boolean gameOver = false;
        List<Card> lastPlayedCards = null;
        int passCount = 0;
        
        while (!gameOver) {
            Long currentPlayerId = gameState.getCurrentPlayerId();
            List<Card> currentPlayerCards = playerCards.get(currentPlayerId);
            boolean isLandlord = currentPlayerId.equals(landlordId);
            
            // 记录当前决策
            PlayDecision decision = new PlayDecision(
                currentPlayerId,
                isLandlord,
                currentPlayerCards,
                null,
                lastPlayedCards,
                AIStrategy.getGameStage(currentPlayerCards.size()),
                "pending"
            );
            
            // AI出牌
            List<Card> cardsToPlay = AIStrategy.decideCards(
                currentPlayerCards,
                lastPlayedCards,
                isLandlord,
                gameState
            );
            
            // 更新决策记录
            decision.playedCards = cardsToPlay;
            decision.strategy = determineStrategy(cardsToPlay, lastPlayedCards, isLandlord);
            gameDecisions.add(decision);
            
            // 处理出牌结果
            if (cardsToPlay.isEmpty()) {
                passCount++;
                if (passCount == 2) {
                    lastPlayedCards = null;
                    passCount = 0;
                }
            } else {
                lastPlayedCards = cardsToPlay;
                currentPlayerCards.removeAll(cardsToPlay);
                passCount = 0;
                
                if (currentPlayerCards.isEmpty()) {
                    gameOver = true;
                    updateGameStats(gameDecisions, currentPlayerId, isLandlord);
                }
            }
            
            // 移动到下一个玩家
            if (!gameOver) {
                int currentIndex = allPlayerIds.indexOf(currentPlayerId);
                int nextIndex = (currentIndex + 1) % allPlayerIds.size();
                gameState.setCurrentPlayerId(allPlayerIds.get(nextIndex));
            }
        }
    }
    
    private static void updateGameStats(List<PlayDecision> decisions, Long winnerId, boolean winnerIsLandlord) {
        gameStats.totalGames++;
        if (winnerIsLandlord) {
            gameStats.landlordWins++;
        } else {
            gameStats.farmerWins++;
        }
        
        // 更新每个决策的胜负情况
        for (PlayDecision decision : decisions) {
            decision.won = (decision.isLandlord == winnerIsLandlord);
            
            if (decision.won) {
                gameStats.strategySuccesses.merge(decision.strategy, 1, Integer::sum);
            } else {
                gameStats.strategyFailures.merge(decision.strategy, 1, Integer::sum);
            }
            
            // 更新平均剩余牌数
            double currentAvg = gameStats.avgRemainingCards.getOrDefault(decision.strategy, 0.0);
            int count = gameStats.strategySuccesses.getOrDefault(decision.strategy, 0) +
                       gameStats.strategyFailures.getOrDefault(decision.strategy, 0);
            double newAvg = (currentAvg * count + decision.remainingCards) / (count + 1);
            gameStats.avgRemainingCards.put(decision.strategy, newAvg);
        }
    }
    
    private static void analyzeAndUpdateStrategies() {
        // 计算每种策略的成功率和效果
        Map<String, StrategyStats> strategyStats = new HashMap<>();
        Map<String, PhaseStats> phaseStats = new HashMap<>(); // 新增：阶段统计
        
        // 分析每个决策
        for (PlayDecision decision : gameStats.playHistory) {
            // 更新策略统计
            StrategyStats stats = strategyStats.computeIfAbsent(
                decision.strategy, k -> new StrategyStats());
            updateStrategyStats(stats, decision);
            
            // 更新阶段统计
            String phaseKey = getPhaseKey(decision);
            PhaseStats phase = phaseStats.computeIfAbsent(
                phaseKey, k -> new PhaseStats());
            updatePhaseStats(phase, decision);
        }
        
        // 更新策略权重
        updateStrategyWeights(strategyStats);
        
        // 更新阶段策略
        updatePhaseStrategies(phaseStats);
        
        // 分析叫分策略
        analyzeAndUpdateBidStrategies();
        
        // 分析关键决策点
        analyzeKeyDecisionPoints();
    }

    private static class PhaseStats {
        Map<String, Integer> strategyUsage = new HashMap<>();
        Map<String, Integer> strategySuccess = new HashMap<>();
        double avgHandStrength = 0;
        int totalDecisions = 0;
    }

    private static String getPhaseKey(PlayDecision decision) {
        String role = decision.isLandlord ? "LANDLORD" : "FARMER";
        String stage = getGameStage(decision.remainingCards);
        String strength = getStrengthLevel(decision.handStrength);
        return role + "_" + stage + "_" + strength;
    }

    private static void updatePhaseStats(PhaseStats stats, PlayDecision decision) {
        stats.totalDecisions++;
        stats.strategyUsage.merge(decision.strategy, 1, Integer::sum);
        if (decision.won) {
            stats.strategySuccess.merge(decision.strategy, 1, Integer::sum);
        }
        stats.avgHandStrength = (stats.avgHandStrength * (stats.totalDecisions - 1) + 
            decision.handStrength) / stats.totalDecisions;
    }

    private static void updatePhaseStrategies(Map<String, PhaseStats> phaseStats) {
        for (Map.Entry<String, PhaseStats> entry : phaseStats.entrySet()) {
            String phase = entry.getKey();
            PhaseStats stats = entry.getValue();
            
            // 计算每个阶段最成功的策略
            Map<String, Double> successRates = new HashMap<>();
            stats.strategyUsage.forEach((strategy, usage) -> {
                int successes = stats.strategySuccess.getOrDefault(strategy, 0);
                double rate = usage > 0 ? (double) successes / usage : 0;
                successRates.put(strategy, rate);
            });
            
            // 更新阶段策略权重
            gameStats.phaseStrategyWeights.put(phase, successRates);
        }
    }

    private static void analyzeKeyDecisionPoints() {
        List<PlayDecision> keyDecisions = findKeyDecisions();
        for (PlayDecision decision : keyDecisions) {
            analyzeDecisionImpact(decision);
        }
    }

    private static List<PlayDecision> findKeyDecisions() {
        List<PlayDecision> keyDecisions = new ArrayList<>();
        
        // 找出关键转折点的决策
        for (int i = 1; i < gameStats.playHistory.size(); i++) {
            PlayDecision prev = gameStats.playHistory.get(i-1);
            PlayDecision curr = gameStats.playHistory.get(i);
            
            // 判断是否是关键决策
            if (isKeyDecision(prev, curr)) {
                keyDecisions.add(curr);
            }
        }
        
        return keyDecisions;
    }

    private static boolean isKeyDecision(PlayDecision prev, PlayDecision curr) {
        // 判断条件：
        // 1. 手牌数量显著变化
        boolean significantChange = Math.abs(prev.remainingCards - curr.remainingCards) >= 4;
        
        // 2. 出牌方式改变（如从单张变成炸弹）
        boolean patternChange = !prev.strategy.equals(curr.strategy);
        
        // 3. 手牌强度显著变化
        boolean strengthChange = Math.abs(prev.handStrength - curr.handStrength) >= 20;
        
        return significantChange || patternChange || strengthChange;
    }

    private static void analyzeDecisionImpact(PlayDecision decision) {
        // 分析决策对游戏结果的影响
        double impact = calculateDecisionImpact(decision);
        
        // 更新决策影响力统计
        String decisionType = getDecisionType(decision);
        gameStats.decisionImpacts.merge(decisionType, impact, Double::sum);
    }

    private static double calculateDecisionImpact(PlayDecision decision) {
        // 基础影响力
        double impact = 1.0;
        
        // 根据不同因素调整影响力
        if (decision.won) {
            impact *= 1.5; // 获胜决策的影响力更大
        }
        
        // 考虑手牌变化
        impact *= (1.0 + (20 - decision.remainingCards) / 20.0);
        
        // 考虑手牌强度
        impact *= (1.0 + decision.handStrength / 100.0);
        
        return impact;
    }

    private static double calculateNewWeight(double winRate, double avgRemainingCards, double avgHandStrength) {
        double weight = 1.0;
        
        // 胜率影响
        weight *= (0.5 + winRate);
        
        // 剩余牌数影响（越少越好）
        weight *= (1.0 + (20 - avgRemainingCards) / 20.0);
        
        // 手牌强度影响
        weight *= (1.0 + avgHandStrength / 200.0);
        
        // 限制权重范围
        return Math.max(0.1, Math.min(2.0, weight));
    }

    private static void analyzeAndUpdateBidStrategies() {
        // 分析每个强度区间的叫分效果
        Map<String, BidStats> bidStats = new HashMap<>();
        
        for (PlayDecision decision : gameStats.playHistory) {
            String strengthKey = String.format("STRENGTH_%d", (decision.handStrength / 10) * 10);
            BidStats stats = bidStats.computeIfAbsent(strengthKey,
                k -> new BidStats());
            
            stats.totalBids++;
            if (decision.won) {
                stats.successfulBids++;
            }
            stats.totalBidValue += decision.bidValue;
        }
        
        // 更新叫分策略
        for (Map.Entry<String, BidStats> entry : bidStats.entrySet()) {
            String strengthKey = entry.getKey();
            BidStats stats = entry.getValue();
            
            double successRate = stats.successfulBids / (double) stats.totalBids;
            double avgBidValue = stats.totalBidValue / (double) stats.totalBids;
            
            // 更新最优叫分策略
            gameStats.bidPatterns.put(strengthKey, calculateOptimalBid(successRate, avgBidValue));
        }
    }

    private static class StrategyStats {
        int totalUses = 0;
        int wins = 0;
        int totalRemainingCards = 0;
        int totalHandStrength = 0;
    }

    private static class BidStats {
        int totalBids = 0;
        int successfulBids = 0;
        int totalBidValue = 0;
    }
    
    private static String determineStrategy(List<Card> playedCards, List<Card> lastPlayedCards, boolean isLandlord) {
        if (playedCards == null || playedCards.isEmpty()) {
            return "PASS";
        }
        
        String baseStrategy = CardPatternUtil.getPattern(playedCards).name();
        String role = isLandlord ? "LANDLORD" : "FARMER";
        return role + "_" + baseStrategy;
    }
    
    private static void logTrainingProgress(int batch) {
        logger.info("训练批次 {}", batch + 1);
        logger.info("总游戏数: {}", gameStats.totalGames);
        logger.info("地主胜率: {}%",
            String.format("%.2f", (double)gameStats.landlordWins / gameStats.totalGames * 100));
        logger.info("农民胜率: {}%",
            String.format("%.2f", (double)gameStats.farmerWins / gameStats.totalGames * 100));
        
        logger.info("\n策略统计:");
        for (String strategy : gameStats.strategyWeights.keySet()) {
            int successes = gameStats.strategySuccesses.getOrDefault(strategy, 0);
            int failures = gameStats.strategyFailures.getOrDefault(strategy, 0);
            double totalAttempts = successes + failures;
            double successRate = totalAttempts > 0 ? (successes / totalAttempts * 100) : 0;
            double weight = gameStats.strategyWeights.get(strategy);
            double avgRemaining = gameStats.avgRemainingCards.getOrDefault(strategy, 0.0);
            
            logger.info("{}: 成功率={}, 权重={}, 平均剩余牌数={}", 
                String.format("%-25s", strategy),  // 策略名称左对齐，占25字符
                String.format("%6.2f%%", successRate),  // 成功率保留2位小数
                String.format("%5.2f", weight),    // 权重保留2位小数
                String.format("%5.1f", avgRemaining)  // 平均剩余牌数保留1位小数
            );
        }
        logger.info(""); // 添加空行分隔每个批次
    }
    
    // 获取训练结果，供AIStrategy使用
    public static Map<String, Double> getStrategyWeights() {
        return new HashMap<>(gameStats.strategyWeights);
    }
    
    public static Map<String, Double> getAverageRemainingCards() {
        return new HashMap<>(gameStats.avgRemainingCards);
    }
    
    private static Map<Long, List<Card>> dealCards() {
        List<Card> allCards = initializeCards();
        Collections.shuffle(allCards);
        
        Map<Long, List<Card>> playerCards = new HashMap<>();
        playerCards.put(1L, new ArrayList<>(allCards.subList(0, 17)));
        playerCards.put(2L, new ArrayList<>(allCards.subList(17, 34)));
        playerCards.put(3L, new ArrayList<>(allCards.subList(34, 51)));
        
        return playerCards;
    }
    
    private static List<Card> initializeCards() {
        return GameUtil.initializeCards(); // 临时返回，实际需要实现
    }
    
    private static Long handleBiddingPhase(GameState gameState, Map<Long, List<Card>> playerCards) {
        int maxBid = 0;
        Long landlordId = null;
        List<Long> playerIds = new ArrayList<>(playerCards.keySet());
        
        // 从当前玩家开始叫分
        Long currentPlayerId = gameState.getCurrentPlayerId();
        int startIndex = playerIds.indexOf(currentPlayerId);
        
        // 记录每个玩家的叫分决策
        Map<Long, Integer> playerBids = new HashMap<>();
        Map<Long, Integer> playerStrengths = new HashMap<>();
        
        // 按顺序叫分
        for (int i = 0; i < playerIds.size(); i++) {
            int index = (startIndex + i) % playerIds.size();
            Long playerId = playerIds.get(index);
            List<Card> cards = playerCards.get(playerId);
            
            // 计算手牌强度
            int strength = AIStrategy.calculateHandStrength(cards);
            playerStrengths.put(playerId, strength);
            
            // 记录叫分
            int bid = AIStrategy.decideBid(cards, maxBid);
            playerBids.put(playerId, bid);
            
            if (bid > maxBid) {
                maxBid = bid;
                landlordId = playerId;
            }
            
            if (bid == 3) break;
        }
        
        // 更新叫分统计
        updateBidStats(playerBids, playerStrengths, landlordId);
        
        if (landlordId != null) {
            gameState.setLandlordId(landlordId);
            // 分发地主牌
            List<Card> landlordCards = initializeCards().subList(51, 54);
            playerCards.get(landlordId).addAll(landlordCards);
        }
        
        return landlordId;
    }
    
    private static void updateBidStats(Map<Long, Integer> playerBids, 
                                     Map<Long, Integer> playerStrengths,
                                     Long landlordId) {
        for (Map.Entry<Long, Integer> entry : playerBids.entrySet()) {
            Long playerId = entry.getKey();
            int bid = entry.getValue();
            int strength = playerStrengths.get(playerId);
            
            // 将强度分段，每10分一个区间
            String strengthKey = String.format("STRENGTH_%d", (strength / 10) * 10);
            
            // 判断叫分是否成功
            boolean isSuccessful = false;
            if (landlordId != null) {
                if (playerId.equals(landlordId)) {
                    // 如果是地主，叫到地主算成功
                    isSuccessful = true;
                } else {
                    // 如果不是地主，没叫到地主且叫分较低算成功
                    isSuccessful = bid < playerBids.get(landlordId);
                }
            }
            
            // 更新统计
            if (isSuccessful) {
                gameStats.bidSuccesses.merge(strengthKey, 1, Integer::sum);
            } else {
                gameStats.bidFailures.merge(strengthKey, 1, Integer::sum);
            }
            
            // 更新叫分模式
            int totalAttempts = gameStats.bidSuccesses.getOrDefault(strengthKey, 0) +
                              gameStats.bidFailures.getOrDefault(strengthKey, 0);
            if (totalAttempts > 0) {
                double successRate = (double)gameStats.bidSuccesses.getOrDefault(strengthKey, 0) / totalAttempts;
                gameStats.bidPatterns.put(strengthKey, successRate);
            }
        }
    }
    
    private static void saveCurrentModel() {
        AIModelPersistence.AIModel model = AIModelPersistence.loadModel();
        model.strategyWeights = new HashMap<>(gameStats.strategyWeights);
        model.averageRemainingCards = new HashMap<>(gameStats.avgRemainingCards);
        
        // 保存叫分相关的统计数据
        model.bidPatterns = new HashMap<>(gameStats.bidPatterns);
        model.bidSuccesses = new HashMap<>();
        model.bidFailures = new HashMap<>();
        
        // 将 String 类型的 key 转换为 Integer
        gameStats.bidSuccesses.forEach((key, value) -> {
            try {
                String[] parts = key.split("_");
                int strength = Integer.parseInt(parts[1]);
                model.bidSuccesses.put(strength, value);
            } catch (Exception e) {
                logger.error("Error converting bid success key: " + key, e);
            }
        });
        
        gameStats.bidFailures.forEach((key, value) -> {
            try {
                String[] parts = key.split("_");
                int strength = Integer.parseInt(parts[1]);
                model.bidFailures.put(strength, value);
            } catch (Exception e) {
                logger.error("Error converting bid failure key: " + key, e);
            }
        });
        
        AIModelPersistence.saveModel(model);
    }

    /**
     * 计算最优叫分策略
     * @param successRate 该强度区间的历史成功率
     * @param avgBidValue 该强度区间的平均叫分值
     * @return 最优叫分值
     */
    private static double calculateOptimalBid(double successRate, double avgBidValue) {
        // 基础叫分倾向
        double optimalBid;
        
        if (successRate >= 0.7) {
            optimalBid = 3.0;  // 高胜率时倾向于叫3分
        } else if (successRate >= 0.5) {
            optimalBid = 2.0;  // 中等胜率时倾向于叫2分
        } else if (successRate >= 0.3) {
            optimalBid = 1.0;  // 较低胜率时倾向于叫1分
        } else {
            optimalBid = 0.0;  // 很低胜率时倾向于不叫
        }
        
        // 考虑历史平均叫分
        double historicalFactor = 0.3;  // 历史因素的权重
        optimalBid = optimalBid * (1 - historicalFactor) + avgBidValue * historicalFactor;
        
        // 根据成功率微调
        double adjustmentFactor = (successRate - 0.5) * 0.5;  // 根据成功率上下浮动最多0.25分
        optimalBid += adjustmentFactor;
        
        // 确保叫分在有效范围内
        return Math.max(0.0, Math.min(3.0, optimalBid));
    }

    /**
     * 更新策略统计数据
     */
    private static void updateStrategyStats(StrategyStats stats, PlayDecision decision) {
        // 更新使用次数
        stats.totalUses++;
        
        // 更新胜利次数
        if (decision.won) {
            stats.wins++;
        }
        
        // 更新剩余牌数统计
        stats.totalRemainingCards += decision.remainingCards;
        
        // 更新手牌强度统计
        stats.totalHandStrength += decision.handStrength;
    }

    /**
     * 更新策略权重
     */
    private static void updateStrategyWeights(Map<String, StrategyStats> strategyStats) {
        for (Map.Entry<String, StrategyStats> entry : strategyStats.entrySet()) {
            String strategy = entry.getKey();
            StrategyStats stats = entry.getValue();
            
            // 计算成功率
            double successRate = stats.wins / (double) stats.totalUses;
            
            // 计算平均剩余牌数
            double avgRemainingCards = stats.totalRemainingCards / (double) stats.totalUses;
            
            // 计算平均手牌强度
            double avgHandStrength = stats.totalHandStrength / (double) stats.totalUses;
            
            // 计算新权重
            double newWeight = calculateNewWeight(successRate, avgRemainingCards, avgHandStrength);
            
            // 更新策略权重
            gameStats.strategyWeights.put(strategy, newWeight);
            
            // 更新平均剩余牌数
            gameStats.avgRemainingCards.put(strategy, avgRemainingCards);
        }
    }

    /**
     * 获取游戏阶段
     */
    private static String getGameStage(int remainingCards) {
        if (remainingCards > 10) {
            return "EARLY";
        } else if (remainingCards > 5) {
            return "MID";
        } else {
            return "LATE";
        }
    }

    /**
     * 获取手牌强度等级
     */
    private static String getStrengthLevel(int handStrength) {
        if (handStrength >= 90) {
            return "VERY_STRONG";
        } else if (handStrength >= 70) {
            return "STRONG";
        } else if (handStrength >= 50) {
            return "MEDIUM";
        } else if (handStrength >= 30) {
            return "WEAK";
        } else {
            return "VERY_WEAK";
        }
    }

    /**
     * 获取决策类型
     */
    private static String getDecisionType(PlayDecision decision) {
        StringBuilder type = new StringBuilder();
        
        // 添加角色
        type.append(decision.isLandlord ? "LANDLORD_" : "FARMER_");
        
        // 添加游戏阶段
        type.append(getGameStage(decision.remainingCards)).append("_");
        
        // 添加策略类型
        type.append(decision.strategy);
        
        return type.toString();
    }
} 